package metamodel.parser;

import metamodel.*;

import java.util.Iterator;

/**
 * Takes a Parse Tree and replaces all unresolved tpye references with
 * object references to the appropriate typedefs (Klazz Objects..)
 * User: felix
 * Date: 18.06.2005
 */
public class ReferenceResolver {
    ClassNode meta;
    private LabelMap labelMap;

    public ReferenceResolver(ClassNode meta) {
        this.meta = meta;
        labelMap = new LabelMap(meta);

        descentRecord(meta);

    }

    /** Traverse the tree of tpyes*/
    private void descentRecord(ClassNode meta) {

        if (meta instanceof PolyClassNode) {
            PolyClassNode polyClazz = (PolyClassNode) meta;
            int index=0;
            for (Iterator iter = polyClazz.getSubClazzes().iterator(); iter.hasNext();) {
                ClassNode classNode =  (ClassNode) iter.next();

                if (classNode instanceof TypeReference) {
                    TypeReference typeReference = (TypeReference) classNode;
                    polyClazz.getSubClazzes().remove(index);
                    polyClazz.getSubClazzes().add(index,resolveType(meta,typeReference));
                    return;

                }
                if (classNode.isPoly()){
                    descentRecord(classNode);
                } else {
                    descentProperties(classNode);
                }
                index++;
            }
        } else{

            descentProperties(meta);
        }
    }

    private void descentProperties(ClassNode meta) {
        for (Iterator iterator = meta.getProperties().iterator(); iterator.hasNext();) {
            Property property = (Property) iterator.next();
            if (property instanceof DeepProperty) {
                DeepProperty deepProperty = (DeepProperty) property;
                if (deepProperty.getElementType() instanceof TypeReference) {
                    TypeReference typeReference = (TypeReference) deepProperty.getElementType();
                    deepProperty.setElementType(resolveType(meta,typeReference));

                }   else {
                    descentRecord(deepProperty.getElementType());
                }
            }
        }
    }


    /** Set the elementType of deppProperty to the Klazz that is referenced by the ReferenceType*/
    private ClassNode resolveType(ClassNode enclosingType, TypeReference typeReference) {
        return labelMap.get(typeReference.getPath());
    }


}
